package com.byron.media.server.utils;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class UdpSender implements Runnable{

    private long frameIndex = 0l;

    private DatagramSocket udpSocket;

    private boolean running = true;

    private BlockingQueue<DataInfo> frameQueue;

//    private List<FrameInfo> frameCache;

    private String broadcastAddress;

    private int seqNum = 0;

    private int port;

    public UdpSender(String broadcastAddress, int port) {
        this.broadcastAddress = broadcastAddress;
        this.port = port;

//        frameCache = new ArrayList<>();
        frameQueue = new LinkedBlockingQueue<>();
        try {
            // 组播用以下的方式
            udpSocket = new MulticastSocket(port);
            ((MulticastSocket)udpSocket).joinGroup(InetAddress.getByName(broadcastAddress));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void run() {
        while(running){
            DataInfo dataInfo = null;
            try {
                dataInfo = frameQueue.take();
            } catch (InterruptedException e) {
                e.printStackTrace();
                if(!running){
                    return;
                }
            }
            if(dataInfo != null){
                // 如果是关键帧则缓存起来
//                if((frameInfo.getFlag() & 0x01) == 1){
//                    frameCache.clear();
//                }
//                frameCache.add(frameInfo);

                //RTP打包并且组播
                if(dataInfo.isVideo()){
                    sendRtpData(dataInfo.getData());
                } else {
                    sendPcmRtpData(dataInfo.getData());
                }
            }
        }

    }

    /**
     * 将帧数据推送给发送器
     * @param dataInfo
     */
    public void pushFrameInfo(DataInfo dataInfo){
        try {
            frameQueue.put(dataInfo);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 用RTP 打包方式组播流媒体数据
     * 时间戳是随意设的，因为此app并不涉及到时间戳，但是如果弄到标准的流媒体上时，要改回来
     */
    void sendPcmRtpData(byte[] data) {
        frameIndex += 1;
        if(RtpHelper.needToMultiPackage(data.length)){
            // 多分包
            List<byte[]> rtps = RtpHelper.packagePcmToMultiRtp(data, 0, data.length, (int) frameIndex, seqNum++);
            for(byte[] rtp : rtps){
                try {
                    DatagramPacket packet = new DatagramPacket(rtp, 0, rtp.length, InetAddress.getByName(broadcastAddress), port);
                    udpSocket.send(packet);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        } else {
            // 单包
            byte[] rtp = RtpHelper.packagePcmToRtp(data, 0, data.length, (int) frameIndex, seqNum++);
            try {
                DatagramPacket packet = new DatagramPacket(rtp, 0, rtp.length, InetAddress.getByName(broadcastAddress), port);
                udpSocket.send(packet);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 用RTP 打包方式组播流媒体数据
     * 时间戳是随意设的，因为此app并不涉及到时间戳，但是如果弄到标准的流媒体上时，要改回来
     */
    void sendRtpData(byte[] data) {

        int start = RtpHelper.findStartCodeIndex(data) + 1;
        frameIndex += 1;

        if(RtpHelper.needToMultiPackage(data.length - start)){
            // 多分包
            List<byte[]> rtps = RtpHelper.packageToMultiRtp(data, start, data.length, (int) frameIndex, seqNum++);
            for(byte[] rtp : rtps){
                try {
                    DatagramPacket packet = new DatagramPacket(rtp, 0, rtp.length, InetAddress.getByName(broadcastAddress), port);
                    udpSocket.send(packet);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        } else {
            // 单包
            byte[] rtp = RtpHelper.packageToRtp(data, start, data.length, (int) frameIndex, seqNum++);
            try {
                DatagramPacket packet = new DatagramPacket(rtp, 0, rtp.length, InetAddress.getByName(broadcastAddress), port);
                udpSocket.send(packet);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭线程
     */
    public void close(){
        running = false;
//        frameCache.clear();
    }

    /**
     * 开启组播线程
     */
    public void start() {
        new Thread(this).start();
    }
}
